// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of dart.core;

/**
 * 持续时间、时间跨度，如27天、4小时、12分钟和3秒。
 *
 * `Duration`表示从一个时间点到另一个时间点的时间差。
 * 如果是一个较晚的时间点和一个较早的时间点，Duration可能是负数。
 *
 * 通过适当的参数，使用类唯一的构造函数创建Duration对象：
 *
 *     Duration fastestMarathon = new Duration(hours:2, minutes:3, seconds:2);
 *
 * Duration是所有各个参数的总和。
 * 这意味着，各个参数的值不受单位限制。
 * 例如，[minutes]的值可以大于59。
 *
 *     assert(fastestMarathon.inMinutes == 123);
 *
 * 各个参数允许使用负值。
 *
 * 使用其中一个属性，例如[inDays]，获取指定单位Duration的整数值。
 * 请注意，返回的值是向下取整（向下舍入）得到的。
 * 例如，
 *
 *     Duration aLongWeekend = new Duration(hours:88);
 *     assert(aLongWeekend.inDays == 3);
 *
 * 该类提供了计算和比较操作的集合，以及一组用于转换时间单位的、实用的const常量。
 *
 * [DateTime]表示一个时间点。
 * [Stopwatch]用于测量时间间隔。
 */
class Duration implements Comparable<Duration> {
  static const int MICROSECONDS_PER_MILLISECOND = 1000;
  static const int MILLISECONDS_PER_SECOND = 1000;
  static const int SECONDS_PER_MINUTE = 60;
  static const int MINUTES_PER_HOUR = 60;
  static const int HOURS_PER_DAY = 24;

  static const int MICROSECONDS_PER_SECOND =
      MICROSECONDS_PER_MILLISECOND * MILLISECONDS_PER_SECOND;
  static const int MICROSECONDS_PER_MINUTE =
      MICROSECONDS_PER_SECOND * SECONDS_PER_MINUTE;
  static const int MICROSECONDS_PER_HOUR =
      MICROSECONDS_PER_MINUTE * MINUTES_PER_HOUR;
  static const int MICROSECONDS_PER_DAY =
      MICROSECONDS_PER_HOUR * HOURS_PER_DAY;


  static const int MILLISECONDS_PER_MINUTE =
      MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE;
  static const int MILLISECONDS_PER_HOUR =
      MILLISECONDS_PER_MINUTE * MINUTES_PER_HOUR;
  static const int MILLISECONDS_PER_DAY =
      MILLISECONDS_PER_HOUR * HOURS_PER_DAY;

  static const int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
  static const int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;

  static const int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;

  static const Duration ZERO = const Duration(seconds: 0);

  /*
   * The value of this Duration object in microseconds.
   */
  final int _duration;

  /**
   * 创建一个Duration对象，该对象的值是各个参数部分的总和。
   *
   * 各个参数的值不受单位限制。例如，[hours]可以大于23。
   *
   * 所有的参数允许负值。
   * 所有参数默认值为0。
   */
  const Duration({int days: 0,
                  int hours: 0,
                  int minutes: 0,
                  int seconds: 0,
                  int milliseconds: 0,
                  int microseconds: 0})
      : this._microseconds(
            MICROSECONDS_PER_DAY * days +
            MICROSECONDS_PER_HOUR * hours +
            MICROSECONDS_PER_MINUTE * minutes +
            MICROSECONDS_PER_SECOND * seconds +
            MICROSECONDS_PER_MILLISECOND * milliseconds +
            microseconds);

  // Fast path internal direct constructor to avoids the optional arguments and
  // [_microseconds] recomputation.
  const Duration._microseconds(this._duration);

  /**
   * 返回新的Duration对象，值为`this`与[other]相加的和。
   */
  Duration operator +(Duration other) {
    return new Duration._microseconds(_duration + other._duration);
  }

  /**
   * 返回新的Duration对象，值为`this`减去[other]的时间差。
   */
  Duration operator -(Duration other) {
    return new Duration._microseconds(_duration - other._duration);
  }

  /**
   * 返回新的Duration对象，值为`this`与[factor]相乘的结果。
   *
   * 请注意，当[factor]是double类型，Duration的值超过53位时，
   * 因为双精度计算的原因，精度会丢失。
   */
  Duration operator *(num factor) {
    return new Duration._microseconds((_duration * factor).round());
  }

  /**
   * 返回新的Duration对象，值为`this`与[quotient]取整的结果。
   *
   * 如果[quotient]是`0`，将抛出异常[IntegerDivisionByZeroException]。
   */
  Duration operator ~/(int quotient) {
    // By doing the check here instead of relying on "~/" below we get the
    // exception even with dart2js.
    if (quotient == 0) throw new IntegerDivisionByZeroException();
    return new Duration._microseconds(_duration ~/ quotient);
  }

  /**
   * 如果`this`小于[other]的值，返回`true`。
   */
  bool operator <(Duration other) => this._duration < other._duration;

  /**
   * 如果`this`大于[other]的值，返回`true`。
   */
  bool operator >(Duration other) => this._duration > other._duration;

  /**
   * 如果`this`小于或等于[other]的值，返回`true`。
   */
  bool operator <=(Duration other) => this._duration <= other._duration;

  /**
   * 如果`this`大于或等于[other]的值，返回`true`。
   */
  bool operator >=(Duration other) => this._duration >= other._duration;

  /**
   * 返回`this`跨越的天数。
   */
  int get inDays => _duration ~/ Duration.MICROSECONDS_PER_DAY;

  /**
   * 返回`this`跨越的小时数。
   *
   * 返回值可以大于23。
   */
  int get inHours => _duration ~/ Duration.MICROSECONDS_PER_HOUR;

  /**
   * 返回`this`跨越的分钟数。
   *
   * 返回值可以大于59。
   */
  int get inMinutes => _duration ~/ Duration.MICROSECONDS_PER_MINUTE;

  /**
   * 返回`this`跨越的秒数。
   *
   * 返回值可以大于59。
   */
  int get inSeconds => _duration ~/ Duration.MICROSECONDS_PER_SECOND;

  /**
   * 返回`this`跨越的毫秒数。
   *
   * 返回值可以大于999。
   */
  int get inMilliseconds => _duration ~/ Duration.MICROSECONDS_PER_MILLISECOND;

  /**
   * 返回`this`跨越的微秒数。
   */
  int get inMicroseconds => _duration;

  /**
   * 如果`this`的值和[other]的值相等（持续时间一样），返回`true`。
   */
  bool operator ==(other) {
    if (other is !Duration) return false;
    return _duration == other._duration;
  }

  int get hashCode => _duration.hashCode;

  /**
   * 将此Duration与[other]进行比较。
   *
   * 如果值相等，则返回0.
   *
   * 如果`this`比[other]时间短，则返回负整数。反之，返回正整数。
   *
   * 一个负值的`Duration`被认为始终比一个正值的`Duration`时间短。
   *
   * 总是如此：`duration1.compareTo(duration2) < 0`，
   * 当且仅当`(someDate + duration1).compareTo(someDate + duration2) < 0`。
   */
  int compareTo(Duration other) => _duration.compareTo(other._duration);

  /**
   * 返回一个字符串来表示此`Duration`。
   *
   * 使用小时、分、秒和微秒，以`HH:MM:SS.mmmmmm`为格式，返回一个字符串。例如，
   *
   *     var d = new Duration(days:1, hours:1, minutes:33, microseconds: 500);
   *     d.toString();  // "25:33:00.000500"
   */
  String toString() {
    String sixDigits(int n) {
      if (n >= 100000) return "$n";
      if (n >= 10000) return "0$n";
      if (n >= 1000) return "00$n";
      if (n >= 100) return "000$n";
      if (n >= 10) return "0000$n";
      return "00000$n";
    }
    String twoDigits(int n) {
      if (n >= 10) return "$n";
      return "0$n";
    }

    if (inMicroseconds < 0) {
      return "-${-this}";
    }
    String twoDigitMinutes = twoDigits(inMinutes.remainder(MINUTES_PER_HOUR));
    String twoDigitSeconds = twoDigits(inSeconds.remainder(SECONDS_PER_MINUTE));
    String sixDigitUs =
        sixDigits(inMicroseconds.remainder(MICROSECONDS_PER_SECOND));
    return "$inHours:$twoDigitMinutes:$twoDigitSeconds.$sixDigitUs";
  }

  /**
   * 判断`this`是否是负数。
   *
   * 负值的`Duration`表示一个较晚的时间点和一个较早的时间点的时间差。
   */
  bool get isNegative => _duration < 0;

  /**
   * 返回一个新的`Duration`对象表示`this`的绝对值。
   *
   * 返回的`Duration`有与`this`相同的长度，但始终是正值。
   */
  Duration abs() => new Duration._microseconds(_duration.abs());

  /**
   * 返回一个新的`Duration`对象表示`this`的负值。
   *
   * 返回的`Duration`有与`this`相同的长度，但是有负号。
   */
  Duration operator -() => new Duration._microseconds(-_duration);
}
